package com.yupi.maker.meta;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.json.JSONUtil;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 *
 * @author su.gd
 * @date 2023-12-03
 */
public class MetaManager {

    /**
     * volatile：确保多线程下可见性（确保多线程在访问该变量时能够看到最新的值）
     *
     * 当我们使用多个线程访问同一个变量时，可能会出现数据不一致的问题，即一个线程在修改了变量值后，另一个线程在访问该变量时看到的是旧的值。
     * 为了解决这个问题，可以使用volatile关键字修饰变量。当一个线程修改了变量的值后，其他线程在访问该变量时会看到最新的值，而不是旧的值。
     */
    private static volatile Meta meta;

    /**
     * 私有构造函数，防止外部实例化对象
     */
    private  MetaManager() {
    }

    public static Meta getMetaObject() {
        // 防止对象获取性能被锁影响
        // 如果添加该判断：后续线程看到meta不为null，所有线程都会直接去执行 return meta;
        // 如果不添加该判断，后续的对象需要排队进入锁之后，然后再判断是否为空
        if (meta == null) {
            // 防止多线程引起的重复实例化
            synchronized (MetaManager.class) {
                // 防止重复实例化
                // 再次添加该判断的原因：
                // 如果说不添加该判断的话，多个线程到达synchronized后，进行排队，
                // 第一个线程获取到锁，然后直接实例化Meta对象
                // 第一个线程执行完之后，第二个线程获取到锁，然后也会直接实例化Meta对象
                // 这样就会造成重复实例化，所以需要再次添加该判断
                if (meta == null) {
                    meta = initMeta();
                }
            }
        }
        return meta;
    }

    /**
     * 将 json 的值填充到实体对象中
     * @return
     */
    private static Meta initMeta() {
        String metaJson = ResourceUtil.readUtf8Str("meta.json");
        Meta newMeta = JSONUtil.toBean(metaJson, Meta.class);
        return newMeta;
    }
}
